package org.jeecg.modules.ncmeapis.template.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.SqlInjectionUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.ncmeapis.template.service.ISysPackTemplatePremsService;
import org.jeecg.modules.ncmeapis.template.service.ISysPackTemplateService;
import org.jeecg.modules.system.controller.SysDictController;
import org.jeecg.modules.system.controller.SysTenantController;
import org.jeecg.modules.system.controller.SysUserPermissionFilterController;
import org.jeecg.modules.system.dto.UserPermissionFilterDTO;
import org.jeecg.modules.system.entity.SysTenantPack;
import org.jeecg.modules.system.entity.SysTenantPackUser;
import org.jeecg.modules.system.model.TreeSelectModel;
import org.jeecg.modules.system.security.DictQueryBlackListHandler;
import org.jeecg.modules.system.service.*;
import org.jeecg.modules.system.service.impl.IdentityService;
import org.jeecg.modules.ncmeapis.template.entity.SysPackTemplate;
import org.jeecg.modules.ncmeapis.template.entity.SysPackTemplatePrems;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 实际为产品包和用户映射的管理
 */
@RestController
@RequestMapping("/system/role")
@Api(tags = "角色管理")
//@BusinessApi
@Slf4j
public class RoleController {
    @Resource
    private SysTenantController sysTenantController;
    @Resource
    private ISysTenantService sysTenantService;
    @Resource
    private ISysTenantPackService sysTenantPackService;

    @Autowired
    private ISysPackTemplateService sysPackTemplateService;
    @Autowired
    private ISysPackTemplatePremsService sysPackTemplatePremsService;
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private SysDictController sysDictController;
    @Autowired
    private ISysDictService sysDictService;
    @Autowired
    private DictQueryBlackListHandler dictQueryBlackListHandler;
    @Autowired
    private IdentityService identityService;
    @Autowired
    private SysUserPermissionFilterController sysUserPermissionFilterController;

    /**
     * 通过角色名称和项目id获取角色id
     *
     * @param roleName  项目角色名称
     * @param projectId 项目id
     * @return
     */
    @ApiOperation(value = "登录-获取项目角色id", notes = "通过角色名称和项目id获取项目角色id，注：如果通过角色名称无法获取项目列表，则不走该接口")
    @GetMapping(value = "/queryById")
    public Result<SysTenantPack> queryByRoleNameAndProjectId(@RequestParam(name = "roleName", required = true) String roleName, @RequestParam(name = "projectId", required = true) Integer projectId) {
        Result<SysTenantPack> result = new Result<>();
        if (oConvertUtils.isEmpty(roleName)) {
            result.error500("项目角色为空！");
        }
        if (oConvertUtils.isEmpty(projectId)) {
            result.error500("项目为空！");
        }
        //------------------------------------------------------------------------------------------------
        //获取登录用户信息
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        String userId = sysUser.getId();
        //是否开启系统管理模块的多租户数据隔离【SAAS多租户模式】, admin给特权可以管理所有租户
//        if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL && !"admin".equals(sysUser.getUsername())){
//            Integer loginSessionTenant = oConvertUtils.getInt(TenantContext.getTenant());
//            if(loginSessionTenant!=null && !loginSessionTenant.equals(Integer.valueOf(userId))){
//                result.error500("无权限访问他人租户！");
//                return result;
//            }
//        }
        //------------------------------------------------------------------------------------------------
        SysTenantPack sysTenantPack = sysPackTemplateService.queryByRoleNameAndProjectId(roleName, projectId);
        if (oConvertUtils.isEmpty(sysTenantPack)) {
            result.error500("未找到对应实体");
        }
        if (sysTenantPack.getPackName().equals(roleName)) {
            result.setResult(sysTenantPack);
            result.setSuccess(true);
        }
        if (oConvertUtils.isEmpty(result.getResult())) {
            result.error500("未找到对应项目角色");
        }
        return result;
    }


    @ApiOperation(value = "登录-获取当前登录用户所有角色名称", notes = "获取所有角色名称")
    @GetMapping(value = "/queryCurrentRoleNames")
    public Result<List<String>> queryCurrentRoleNames() {
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        if (oConvertUtils.isEmpty(sysUser)) {
            return Result.error("请登录后再获取角色信息");
        }
        Set<String> roles = sysUserService.getUserRoleNamesSet(sysUser.getUsername());
        List<SysTenantPack> sysTenantPacks = sysTenantPackService.getByUserId(sysUser.getId());
        Set<String> packRoles = sysTenantPacks.stream().map(SysTenantPack::getPackName).collect(Collectors.toSet());
        roles.addAll(packRoles);
        List<String> roleNameList = new ArrayList<>(roles);
        return Result.ok(roleNameList);
    }

    @ApiOperation(value = "登录-根据角色名称获得当前登录用户项目id列表", notes = "根据角色名称获得项目id列表")
    @GetMapping(value = "/getProjectIdByRoleName")
    public Result<List<JSONObject>> getProjectIdByRoleName(@RequestParam(name = "roleName") String roleName) {
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        List<SysTenantPack> sysTenantPacks = sysTenantPackService.getByUserId(sysUser.getId());
        LambdaQueryWrapper<SysTenantPack> lqw = new LambdaQueryWrapper<>();
        lqw.eq(SysTenantPack::getPackName, roleName);
        List<SysTenantPack> list = sysTenantPackService.list(lqw);
        //两个List取交集
        List<SysTenantPack> intersection = sysTenantPacks.stream().filter(list::contains).collect(Collectors.toList());
        List<Integer> tenantIds = intersection.stream().map(SysTenantPack::getTenantId).collect(Collectors.toList());
        List<JSONObject> collect = sysTenantService.listByIds(tenantIds).stream().map(sysTenant -> {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("projectId", sysTenant.getId());
            jsonObject.put("projectName", sysTenant.getName());
            return jsonObject;
        }).collect(Collectors.toList());
        return Result.ok(collect);
    }

    /**
     * 根据角色模板id和项目id，为指定用户授权项目角色
     *
     * @param templateId 项目角色模板id
     * @param projectId  项目id
     * @return
     */
    @ApiOperation(value = "为用户授权项目角色", notes = "据角色模板id和项目id，为指定用户授权项目角色")
    @GetMapping(value = "/authorize")
    @RequiresPermissions("system:role:authorize")
    public Result<SysTenantPack> authorize(@RequestParam(name = "templateId", required = true) String templateId, @RequestParam(name = "projectId", required = true) Integer projectId,
                                           @RequestParam(name = "userId", required = true) String userId) {
        SysPackTemplate sysPackTemplate = sysPackTemplateService.getById(templateId);
        List<SysPackTemplatePrems> sysPackTemplatePrems = sysPackTemplatePremsService.selectByMainId(templateId);
        List<String> collect = sysPackTemplatePrems.stream().map(SysPackTemplatePrems::getPermissionId).collect(Collectors.toList());
        String permissionIds = String.join(",", collect);
        if (oConvertUtils.isEmpty(templateId) || oConvertUtils.isEmpty(sysPackTemplate)) {
            return Result.error(500, "项目角色模板为空！");
        }
        if (oConvertUtils.isEmpty(projectId)) {
            return Result.error(500, "项目为空！");
        }
        //将用户添加到项目中
        sysTenantService.invitationUserJoin(projectId.toString(), userId);
        //为项目添加产品包，并为用户添加产品包
        SysTenantPack sysTenantPack = new SysTenantPack();
        BeanUtils.copyProperties(sysPackTemplate, sysTenantPack);
        sysTenantPack.setId(null);
        sysTenantPack.setTenantId(projectId);
        sysTenantPack.setStatus("1");
        sysTenantPack.setPermissionIds(permissionIds);
        sysTenantPackService.addPackPermission(sysTenantPack);
        SysTenantPackUser sysTenantPackUser = new SysTenantPackUser(projectId, sysTenantPack.getId(), userId);
        sysTenantPackUser.setPackName(sysTenantPack.getPackName());
        sysTenantPackUser.setRealname(sysUserService.getById(userId).getRealname());
        sysTenantService.addTenantPackUser(sysTenantPackUser);
        //------------------------------------------------------------------------------------------------
        //获取登录用户信息
//        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
//        String currentUserId = sysUser.getId();
//        //是否开启系统管理模块的多租户数据隔离【SAAS多租户模式】, admin给特权可以管理所有租户
//        if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL && !"admin".equals(sysUser.getUsername())){
//            Integer loginSessionTenant = oConvertUtils.getInt(TenantContext.getTenant());
//            if(loginSessionTenant!=null && !loginSessionTenant.equals(Integer.valueOf(currentUserId))){
//                result.error500("无权限访问他人租户！");
//                return result;
//            }
//        }
        return Result.ok(sysTenantPack);
    }

    @AutoLog(value = "用户权限过滤编辑")
    @ApiOperation(value = "用户权限过滤编辑", notes = "用户权限过滤编辑")
    @RequiresPermissions("system:permissionFilter:edit")
    @PutMapping(value = "/edit")
    public Result<String> edit(@RequestBody UserPermissionFilterDTO userPermissionFilterDTO) {
        return sysUserPermissionFilterController.edit(userPermissionFilterDTO);
    }

    /**
     * 为项目添加用户(测试用)
     *
     * @param ids
     * @param userId
     * @return
     */
//    @ApiOperation(value = "邀请用户",notes = "邀请用户")
    @PutMapping("/invitationUserJoin")
    @RequiresPermissions("system:tenant:invitation:user")
    public Result<String> invitationUserJoin(@RequestParam("ids") String ids, @RequestParam("userId") String userId) {
        sysTenantService.invitationUserJoin(ids, userId);
        return Result.ok("邀请用户成功");
    }

    /**
     * 【接口签名验证】
     * 根据表名——显示字段-存储字段 pid 加载树形数据
     */
    @SuppressWarnings("unchecked")
    @ApiOperation(value = "加载树形菜单数据(带过滤)", notes = "加载树形菜单数据(根据产品包id进行过滤)，header中需传入X-Tenant-Pack-Id")
    @GetMapping(value = "/loadTreeDataFiltered")
    public Result<List<TreeSelectModel>> loadTreeDataFiltered(@RequestParam(name = "pid", required = false) String pid, HttpServletRequest request) {
        String tbname = "sys_permission";
        String code = "id";
        String pidField = "parent_id";
        String text = "name";
        String condition = "";
        int converIsLeafVal = 1;
        String hasChildField = "";
        String sign = null;
        // Todo 目前获取md5加密的PackId有错误，后续更改为MD5加密PackId统一修改
        String tenantPackId = request.getHeader(CommonConstant.X_TENANT_PACK_ID);
        if (oConvertUtils.isEmpty(tenantPackId)) {
            return Result.error(500, "请求头中未包含X-Tenant-Pack-Id");
        }
//        String tenantPackId = "1734555705348542465";
        Result<List<TreeSelectModel>> result = new Result<List<TreeSelectModel>>();
        Map<String, String> query = null;
        if (oConvertUtils.isNotEmpty(condition)) {
            query = JSON.parseObject(condition, Map.class);
        }
        // SQL注入漏洞 sign签名校验(表名,label字段,val字段,条件)
        String dictCode = tbname + "," + text + "," + code + "," + condition;
        SqlInjectionUtil.filterContent(dictCode);
        //update-begin-author:scott date:20230723 for:【issues/5173】SQL注入
        if (!dictQueryBlackListHandler.isPass(dictCode)) {
            return result.error500(dictQueryBlackListHandler.getError());
        }
        //update-end-author:scott date:20230723 for:【issues/5173】SQL注入
        List<TreeSelectModel> ls = sysDictService.queryTreeListByPackId(query, tbname, text, code, pidField, pid, hasChildField, converIsLeafVal, tenantPackId);
        result.setSuccess(true);
        result.setResult(ls);
        return result;
    }

    /**
     * 【接口签名验证】
     * 根据表名——显示字段-存储字段 pid 加载树形数据
     */
    @SuppressWarnings("unchecked")
    @ApiOperation(value = "加载树形菜单数据", notes = "加载树形菜单数据")
    @GetMapping(value = "/loadTreeData")
    public Result<List<TreeSelectModel>> loadTreeData(@RequestParam(name = "pid", required = false) String pid, HttpServletRequest request) {
        String tbname = "sys_permission";
        String code = "id";
        String pidField = "parent_id";
        String text = "name";
        String condition = "";
        int converIsLeafVal = 1;
        String hasChildField = "";
        String sign = null;
        String tenantPackId = identityService.getTenantPackIdByRequest();
//        String tenantPackId = "1734555705348542465";
        Result<List<TreeSelectModel>> result = new Result<List<TreeSelectModel>>();
        Map<String, String> query = null;
        if (oConvertUtils.isNotEmpty(condition)) {
            query = JSON.parseObject(condition, Map.class);
        }
        // SQL注入漏洞 sign签名校验(表名,label字段,val字段,条件)
        String dictCode = tbname + "," + text + "," + code + "," + condition;
        SqlInjectionUtil.filterContent(dictCode);
        //update-begin-author:scott date:20230723 for:【issues/5173】SQL注入
        if (!dictQueryBlackListHandler.isPass(dictCode)) {
            return result.error500(dictQueryBlackListHandler.getError());
        }
        //update-end-author:scott date:20230723 for:【issues/5173】SQL注入
        List<TreeSelectModel> ls = sysDictService.queryTreeListByPackId(query, tbname, text, code, pidField, pid, hasChildField, converIsLeafVal, tenantPackId);
        result.setSuccess(true);
        result.setResult(ls);
        return result;
    }

    /**
     * 【接口签名验证】
     * 根据字典code加载字典text 返回
     *
     * @param keys    要查询的key
     * @param request
     * @return
     */
    @ApiOperation(value = "树形菜单-筛选字符串结果", notes = "树形菜单-筛选字符串结果，用于筛选完菜单后在权限列表框中显示")
    @GetMapping(value = "/loadDictItem/{dictCode}")
    public Result<List<String>> loadDictItem(@RequestParam(name = "key") String keys, HttpServletRequest request) {
        String dictCode = "sys_permission,name,id";
        boolean delNotExist = true;
        String sign = null;
        Result<List<String>> result = new Result<>();
        return sysDictController.loadDictItem(dictCode, keys, sign, delNotExist, request);
    }

    /**
     * 产品包分页列表查询
     *
     * @param sysTenantPack
     * @param pageNo
     * @param pageSize
     * @param req
     * @return
     */
    @ApiOperation(value = "项目角色分页列表查询", notes = "可获取项目角色信息以及相关角色的权限ids")
    @GetMapping(value = "/packList")
    @RequiresPermissions("system:tenant:packQuery")
    public Result<IPage<SysTenantPack>> queryPackPageList(SysTenantPack sysTenantPack,
                                                          @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                                          @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                                          HttpServletRequest req) {
        return sysTenantController.queryPackPageList(sysTenantPack, pageNo, pageSize, req);
    }

}
